#include "snake_room.h"
#include <QPainter>
#include <QPushButton>
#include <QDebug>
#include <QTimer>
#include <QSound>
#include <QMessageBox>
#include <QDialogButtonBox>
#include "snake_select.h"
#include <QFile>

Snake_room::Snake_room(QWidget *parent) : QWidget(parent)
{
    this->setWindowIcon(QIcon(":/res/35.png"));
    this->setWindowTitle("贪吃蛇游戏");

    //开始暂停按钮
    QPushButton* strbut=new QPushButton(this);
    QPushButton* stopbut=new QPushButton(this);
    strbut->setText("开始");
    stopbut->setText("暂停");
    QFont font("楷体",30);
    strbut->setFont(font);
    stopbut->setFont(font);
    strbut->move(1000,150);
    stopbut->move(1000,250);
    //设置开始/暂停按钮槽函数
    //由于开始、暂停按钮关系到定时器，所以先初始化定时器
    timer=new QTimer(this);
    sound=new QSound(":/res/Trepak.wav",this);  //设置背景音乐
    connect(strbut,&QPushButton::clicked,this,[=](){
        QSound::play(":/res/clicked.wav");
        timer->start(snake_speed);
        sound->play();
        sound->setLoops(-1);    //设置背景音乐循环播放
        IsStart=true;
    });
    connect(stopbut,&QPushButton::clicked,this,[=](){
        timer->stop();
        sound->stop();
        IsStart=false;
        QSound::play(":/res/clicked.wav");
    });

    //控制蛇移动方向按钮
    QPushButton* up=new QPushButton(this);
    QPushButton* down=new QPushButton(this);
    QPushButton* left=new QPushButton(this);
    QPushButton* right=new QPushButton(this);
    up->setFixedSize(60,60);        //设置基础按钮大小
    down->setFixedSize(60,60);
    left->setFixedSize(60,60);
    right->setFixedSize(60,60);
    up->setIcon(QIcon(":/res/2.png"));      //设置图片内容
    down->setIcon(QIcon(":/res/4.png"));
    left->setIcon(QIcon(":/res/1.png"));
    right->setIcon(QIcon(":/res/3.png"));
    up->move(1020,450);     //设置按钮位置
    down->move(1020,510);
    left->move(960,510);
    right->move(1080,510);
    //设置蛇移动按钮的快捷键
    up->setShortcut(QKeySequence("w"));
    down->setShortcut(QKeySequence("s"));
    left->setShortcut(QKeySequence("a"));
    right->setShortcut(QKeySequence("d"));
    //信号槽,按下按键更新蛇移动方向
    connect(up,&QPushButton::clicked,this,[=](){
        //如果当前方向为下，则无效，因为不能掉头
        if(snake_dirt!=Snake_Direction::DOWN)
            snake_dirt=Snake_Direction::UP;
    });
    connect(down,&QPushButton::clicked,this,[=](){
        //如果当前方向为下，则无效，因为不能掉头
        if(snake_dirt!=Snake_Direction::UP)
            snake_dirt=Snake_Direction::DOWN;
    });
    connect(left,&QPushButton::clicked,this,[=](){
        //如果当前方向为下，则无效，因为不能掉头
        if(snake_dirt!=Snake_Direction::RIGHT)
            snake_dirt=Snake_Direction::LEFT;
    });
    connect(right,&QPushButton::clicked,this,[=](){
        //如果当前方向为下，则无效，因为不能掉头
        if(snake_dirt!=Snake_Direction::LEFT)
            snake_dirt=Snake_Direction::RIGHT;
    });

    //利用定时器来实现蛇的移动
    //用QTimer的timeout
    connect(timer,&QTimer::timeout,this,[=](){
        //计算分数
        bool Iseat=false;   //判断是否吃了食物
        if(snake_list.front().x()==point_food.x()&&snake_list.front().y()==point_food.y())  //如果蛇头与食物碰撞
        {
            Iseat=true;
            scorce++;
            CreatFood();
            //qDebug()<<scorce;
        }

        //根据蛇的移动方向来进入不同的case语句
        switch (snake_dirt) {
        case Snake_Direction::UP:
            moveUp();
            break;
        case Snake_Direction::DOWN:
            moveDown();
            break;
        case Snake_Direction::LEFT:
            moveLeft();
            break;
        case Snake_Direction::RIGHT:
            moveRight();
            break;
        }

        //判断是否吃食物，吃了则不用删除最后一个新加的节点
        //因为上述move会增加一个节点
        if(!Iseat)
        {
            snake_list.pop_back();
        }
        else    //吃到了
            QSound::play(":/res/eatfood.wav");
        //完成上述逻辑后再更新一下窗口，重新绘制窗口内容，实现移动的效果
        update();
    });

    //游戏退出按钮
    QPushButton* exit=new QPushButton(this);
    exit->setText("退出游戏");
    exit->setIcon(QIcon(":/res/ex.png"));
    QFont ft("楷体",20);
    exit->setFont(ft);
    exit->move(950,700);
    //创建退出消息框
    QMessageBox* box=new QMessageBox(this);
    QPushButton* ok=new QPushButton(box);   //创建两个按钮
    QPushButton* cancle=new QPushButton(box);
    box->setWindowTitle("退出游戏");
    box->setText("是否退出游戏？");
    box->addButton(ok,QMessageBox::AcceptRole);
    box->addButton(cancle,QMessageBox::RejectRole);
    box->setIcon(QMessageBox::Question);
    ok->setText("Ok");
    cancle->setText("Cancle");
    //给ok按钮设置信号槽
    connect(ok,&QPushButton::clicked,this,[=](){this->close();});
    //将exit按钮连接上
    connect(exit,&QPushButton::clicked,this,[=](){
        box->exec();    //不用show用exec，模态
        sound->stop();
        NewHistory();   //退出时保存战绩
    });

    //返回大厅按钮
    QPushButton* ret=new QPushButton(this);
    ret->setText("返回大厅");
    ret->setFont(ft);
    ret->move(965,750);
    connect(ret,&QPushButton::clicked,this,[=](){
        this->close();
        Snake_select* select=new Snake_select();
        select->setGeometry(this->geometry());
        QSound::play(":/res/clicked.wav");
        select->show();
        sound->stop();
        NewHistory();   //返回大厅也要保存一下战绩
    });

    //初始化蛇链表
    //蛇刚开始有三节，蛇头、蛇身、蛇尾
    snake_list.push_back(QRect(this->width()/2,this->height()/2,snake_width,snake_hight));
    moveUp();
    moveUp();

    //初始化食物
    CreatFood();

}

//绘制事件重写
void Snake_room::paintEvent(QPaintEvent *event)
{
    (void)event;
    //绘制基本游戏界面
    QPainter painter(this);
    //创建绘制工具
    QPixmap pix;
    // 绘制游戏界面
    //给QPixmap绘制工具添加内容
    pix.load(":/res/game_room.png");
    //我们设置的窗口大小为1200*900，左边为游戏界面为900*900，右边为控制界面
    painter.drawPixmap(0,0,900,this->height(),pix);
    //绘制右边控制界面
    pix.load(":/res/bg1.png");  //更新pix
    painter.drawPixmap(900,0,this->width()-900,this->height()+20,pix);

    //绘制蛇
    //先判断蛇头是朝向什么方向，再选择我们需要的蛇头
    if(snake_dirt==Snake_Direction::UP)
    {
        pix.load(":/res/up.png");
    }else if(snake_dirt==Snake_Direction::DOWN)
    {
        pix.load((":/res/down.png"));
    }else if(snake_dirt==Snake_Direction::LEFT)
    {
        pix.load(":/res/left.png");
    }else
    {
        pix.load(":/res/right.png");
    }
    //画蛇头
    auto snake_head=snake_list.front();     //获取头节点
    painter.drawPixmap(snake_head.x(),snake_head.y(),snake_width,snake_hight,pix);
    //画蛇身
    pix.load(":/res/Bd.png");
    for(int i=1;i<snake_list.size()-1;i++)
    {
        auto snake_body=snake_list.at(i);    //通过at函数获取后面的节点
        painter.drawPixmap(snake_body.x(),snake_body.y(),snake_body.width(),snake_body.height(),pix);
    }
    //画蛇尾
    //虽然蛇身和蛇尾长得一样，但是为了后续去更好地删除或添加节点，还是需要拆分的
    auto snake_back=snake_list.back();
    painter.drawPixmap(snake_back.x(),snake_back.y(),snake_back.width(),snake_back.height(),pix);

    //绘制食物
    pix.load(":/res/food.bmp");
    painter.drawPixmap(point_food.x(),point_food.y(),point_food.width(),point_food.height(),pix);

    //绘制分数
    //绘制分数背景
    pix.load(":/res/sorce_bg.png");
    painter.drawPixmap(950,50,200,80,pix);
    //用QPen钢笔绘制分数
    QPen pen(Qt::black);    //设置钢笔颜色
    painter.setPen(pen);
    QFont font("楷体",20);    //设置画笔的字体设置
    painter.setFont(font);
    painter.drawText(1070,110,QString("%1").arg(scorce));

    //由于构造函数中的update，会让绘制事件不断执行
    //所以在这里判断游戏是否结束就行
    if(!ChackFail())
    {
        //显示GameOver
        QPen pen1(Qt::red);
        QFont ft("楷体",100);
        painter.setPen(pen1);
        painter.setFont(ft);
        painter.drawText(this->width()*0.1,this->height()*0.6,"Game Over");
        timer->stop();
        sound->stop();
        QSound::play(":/res/gameover.wav");
        NewHistory();
    }
}

//向上移动  移动时会变长
void Snake_room::moveUp()
{
    //设置两个坐标，表示左上角和右下角坐标，确定一个正方形
    //因为QRect有个构造函数，可以根据左上角坐标和左下角坐标构造Rect对象
    QPoint leftTop;
    QPoint rightButtom;

    auto snake_head=snake_list.front(); //取出蛇的头节点
    //头节点是QRect类型，默认的x和y是左上角坐标，我们根据对左上角坐标判断蛇头的新位置
    int headX=snake_head.x();
    int headY=snake_head.y();

    if(headY<=0) //向上超出窗口了   穿墙
    {
        //向上运动，X轴位置不变，Y轴变到最下面
        leftTop=QPoint(headX,this->height()-snake_hight);  //窗口大小-蛇头大小
    }else{
        leftTop=QPoint(headX,headY-snake_hight);
    }
    rightButtom=leftTop+QPoint(snake_width,snake_hight);

    snake_list.push_front(QRect(leftTop,rightButtom));  //在新位置头插一个节点
}
//向下移动
void Snake_room::moveDown()
{
    QPoint leftTop;
    QPoint rightDown;

    auto snake_head=snake_list.front();
    int headX=snake_head.x();
    int headY=snake_head.y();

    if(headY>=this->height()-snake_hight)
    {
        leftTop=QPoint(headX,0);
    }else{
        leftTop=QPoint(headX,headY+snake_hight);
    }

    rightDown=leftTop+QPoint(snake_width,snake_hight);

    snake_list.push_front(QRect(leftTop,rightDown));
}
//向左移动
void Snake_room::moveLeft()
{
    QPoint leftTop;
    QPoint rightDown;

    auto snake_head=snake_list.front();
    int headX=snake_head.x();
    int headY=snake_head.y();

    if(headX<=0)
    {
        leftTop=QPoint(900-snake_width,headY);
    }
    else
    {
        leftTop=QPoint(headX-snake_width,headY);
    }
    rightDown=leftTop+QPoint(snake_width,snake_hight);
    snake_list.push_front(QRect(leftTop,rightDown));
}
//向右移动
void Snake_room::moveRight()
{
    QPoint leftTop;
    QPoint rightDown;

    auto snake_head=snake_list.front();
    int headX=snake_head.x();
    int headY=snake_head.y();

    if(headX>=900-snake_width)  //900为我们自己的游戏画面大小
    {
        leftTop=QPoint(0,headY);
    }
    else
    {
        leftTop=QPoint(headX+snake_width,headY);
    }
    rightDown=leftTop+QPoint(snake_width,snake_hight);
    snake_list.push_front(QRect(leftTop,rightDown));
}

void Snake_room::moveSpeed(int speed=200)
{
    snake_speed=speed;
}
//随机位置创建食物
void Snake_room::CreatFood()
{
    //这样创建会导致位置和蛇头不是正好的，不会完美重叠，不好判断是否吃到食物
//    QPoint leftTop;
//    QPoint rightDown;
//    int foodx=qrand()%900-snake_width;
//    int foody=qrand()%900-snake_hight;
//    leftTop=QPoint(foodx,foody);
//    rightDown=leftTop+QPoint(snake_width,snake_hight);
//    point_food=QRect(leftTop,rightDown);
    point_food=QRect(qrand()%(900/snake_width)*snake_width,qrand()%(900/snake_hight)*snake_hight,snake_width,snake_hight);
}

void Snake_room::NewHistory()
{
    //游戏结束，判断当前分数是否比历史战绩高   同理游戏暂停和返回大厅也检测一下分数
    QFile file("D:/qt_learn/Snake/res/history.txt");
    if(file.open(QFile::ReadOnly))  //先读数据，防止写的时候部分覆盖原来的数据
    {
        int date=file.readLine().toUInt();
        file.close();
        if(date<scorce)
        {
            QFile file_w("D:/qt_learn/Snake/res/history.txt");
            file_w.open(QFile::WriteOnly);
            qDebug()<<"scorce="<<scorce;
            file_w.write(QString::number(scorce).toUtf8());
            file_w.close();
        }
    }else
    {
        qDebug()<<"open history fail";
    }
}

bool Snake_room::ChackFail()
{
    for(int i=0;i<snake_list.size();i++)
    {
        for(int j=i+1;j<snake_list.size();j++)
        {
            if(snake_list.at(i).x()==snake_list.at(j).x()&&snake_list.at(i).y()==snake_list.at(j).y())
                return false;
        }
    }
    return true;
}

